/***************************************************
 ** Create by Hasaki on 2021/11/25.
 ** This file is part of the CSTL project.
 ** This file follows version 3 of GNU License.
 ** About GNU, see <https://www.gnu.org/licenses/>.
 **
 ** 本文件由Hasaki(间宫羽咲sama)于2021年11月25日创建。
 ** 本文件是CSTL(C-STL)项目的一部分。
 ** 本文件遵从GNU-v3协议。
 ** 关于GNU协议，见<https://www.gnu.org/licenses/>。
 ***************************************************/
#include "HskVector.h"
#include "HskLogConfig.h"

Vector* VecCreate(const size_t typesize, const size_t size, size_t capacity) {
  // 正常情况下size应小于等于capacity，如果不满足，报参数异常警告
  if (size > capacity){
    HSK_LOG_PARM_WARN(printf("[VecCreate PARM WARN]: size %zu > capacity %zu is unexpected, already let capacity = size.\n", size, capacity));
    capacity = size;
  }
  HSK_LOG_DEBUG(printf("[VecCreate Debug]: size = %zu, capacity = %zu.\n", size, capacity));

  // 尝试初始化vec，分配3个NULL+1个0
  Vector *vec = (Vector *)calloc(4, sizeof(void *));  // 如果calloc失败，返回NULL并严重警告
  ASSERT_MALLOC_NOT_NULL(vec, printf("[VecCreate CRIT WARN]: Bad calloc of vec, size = %zu, capacity = %zu.\n", size, capacity), NULL)

  // 尝试给vec分配capacity个typesize的空间，每个初始为0
  vec->_tsize = typesize;
  if (capacity != 0) {  // capacity为0就不用分配了
    vec->_begin = (void *)calloc(capacity, typesize); // 如果calloc失败，free(vec)后返回NULL并严重警告
    ASSERT_MALLOC_NOT_NULL(vec->_begin, printf("[VecCreate CRIT WARN]: Bad calloc of vec->_begin, size = %zu, capacity = %zu.\n", size, capacity);
                                        free(vec);, NULL)
    vec->_end   = vec->_begin + typesize * size;
    vec->_last  = vec->_begin + typesize * capacity;
  }
  return vec;
}

void VecClean(Vector *_this) {
  ASSERT_THIS_NOT_NULL(_this, "VecClean", , );   // 如果是空指针就不用free了，防止执行_this->_begin

  free(_this->_begin);  // 析构数组
  free(_this);          // 析构Vector类
}

void VecDelete(Vector **_pthis) {
  ASSERT_THIS_NOT_NULL(_pthis, "VecDelete", , );

  VecClean(*_pthis);
  *_pthis = NULL;
}

void VecReCapa(Vector *const _this, size_t newCapa) {
  ASSERT_THIS_NOT_NULL(_this, "VecReCapa", , );   // 如果是空指针，认为是非法操作，必须先Create一个对象

  size_t size = (_this->_end - _this->_begin) / _this->_tsize;
  size_t newSize = size > newCapa ? newCapa : size;
  HSK_LOG_DEBUG(printf("[VecReCapa DEBUG]: size = %zu, newCapa = %zu, newSize = %zu.\n", size, newCapa, newSize));

  // newCapa < size意味着数据空间被缩小了，这里报警告方便debug
  HSK_LOG_WARN(
  if (newCapa < size)
    printf("[VecReCapa WARN]: newCapa %zu < size %zu, so size will be cropped.\n", newCapa, size);
  )

  // 如果新容量是0，直接return，避免malloc(0)这种UB
  if (newCapa == 0) {
    free(_this->_begin);
    _this->_begin = NULL;
    _this->_end   = NULL;
    _this->_last  = NULL;
    return;
  }

  // 将Vec(size, capa)扩/缩容为Vec(newSize, newCapa)
  void *newVec = calloc(newCapa, _this->_tsize);  // 其实用malloc+memcpy开销会更小，但这里偷懒了
  ASSERT_MALLOC_NOT_NULL(newVec, printf("[VecReCapa CRIT WARN]: Bad calloc of newVec, capacity = %zu.\n", newCapa), )
  
  memcpy(newVec, _this->_begin, newSize * _this->_tsize);
  free(_this->_begin);    // 释放旧空间，指向新分配的newVec
  _this->_begin = newVec;
  _this->_end   = newVec + _this->_tsize * newSize;
  _this->_last  = newVec + _this->_tsize * newCapa;
}

void VecReSize(Vector *const _this, size_t newSize) {
  ASSERT_THIS_NOT_NULL(_this, "VecReSize", , );   // 如果是空指针，认为是非法操作，必须先Create一个对象

  size_t size = (_this->_end  - _this->_begin) / _this->_tsize;
  size_t capa = (_this->_last - _this->_begin) / _this->_tsize;

  if (newSize < size) {     // 如果尺寸被缩减了
    HSK_LOG_WARN(printf("[VecReSize WARN]: newSize %zu < size %zu, so size will be cropped.\n", newSize, size));
    void *newSizePtr = _this->_begin + _this->_tsize * newSize;
    memset(newSizePtr, 0, _this->_end - newSizePtr);
    _this->_end = newSizePtr;
  }
  else if (newSize <= capa) { // 如果没必要扩容，直接改end指针就行
    _this->_end = _this->_begin + _this->_tsize * newSize;
  }
  else {    // newSize > capa，要扩容，调用VecReCapa图省事
    VecReCapa(_this, newSize);
    _this->_end = _this->_last;
  }
}

void VecHandleAll(Vector *const _this, void (*handle)(Vector *const, void *, size_t)) {
  ASSERT_THIS_NOT_NULL(_this, "VecHandleAll", , );

  size_t seq   = 0;
  void *it     = _this->_begin;
  void *endPtr = _this->_end;
  // 用<是为了防止_this->end意外改变导致死循环
  // 严禁handle对this的size或者capa进行任何修改！！！
  while (it != endPtr) {
    handle(_this, it, seq);
    it += _this->_tsize;
    ++ seq;
    // 该警告用于检查handle函数是否改变了endPtr
    HSK_LOG_WARN(
    if (endPtr != _this->_end) {
      printf("[VecHandleAll WARN]: _this->_end accidently be changed in handle.\n");
      return;
    }
    )
  }
}

void VecPush(Vector *const _this, const void *elem) {
  ASSERT_THIS_NOT_NULL(_this, "VecPush", , );

  if (_this->_end == _this->_last) {  // 如果满了，按照2^n向上取整的方式分配空间
    size_t capa =  (_this->_last - _this->_begin) / _this->_tsize;
    VecReCapa(_this, HskPower2Ceil(capa + 1));
  }
  memcpy(_this->_end, elem, _this->_tsize);
  _this->_end += _this->_tsize;
}

void VecPushSlice(Vector *const _this, const void *elemBeg, const void *elemEnd) {
  ASSERT_THIS_NOT_NULL(_this, "VecPushSlice", , );

  size_t pushByteSize = elemEnd - elemBeg;

  size_t remains = (elemEnd - elemBeg) % _this->_tsize;
  pushByteSize -= remains; // 确保能整除，正常remains为0
  // 如果pushByteSize不能整除_this->_tsize，那么极可能是因为类型不匹配
  HSK_LOG_PARM_WARN(
  if (remains != 0)
    printf("[VecPushSlice PARM WARN]: (elemEnd - elemBeg) not match _this->_tsize.\n");
  )

  if (_this->_end + pushByteSize > _this->_last) {  // 如果空间不够，按照2^n向上取整的方式分配空间
    size_t newCapa = HskPower2Ceil((_this->_end - _this->_begin + pushByteSize) / _this->_tsize);
    VecReCapa(_this, newCapa);
  }
  memcpy(_this->_end, elemBeg, pushByteSize);
  _this->_end += pushByteSize;
}

void VecDelN(Vector *const _this, const size_t _N) {
  ASSERT_THIS_NOT_NULL(_this, "VecDelN", , );

  void *newEnd = _this->_end - _this->_tsize * _N;
  if (newEnd <= _this->_begin) {  // 相当于全部删除
    HSK_LOG_WARN(printf("[VecDelN WARN]: size %zu but delete %zu, so all space be freed.\n", VecGetSize(_this), _N));
    free(_this->_begin);
    _this->_begin = NULL;
    _this->_end   = NULL;
    _this->_last  = NULL;
  }
  else {
    memset(newEnd, 0, _this->_end - newEnd);
    _this->_end = newEnd;
  }
}

void* VecGet(const Vector *const _this, const size_t N) {
  ASSERT_THIS_NOT_NULL(_this, "VecGet", , 0);
  // 越界检查， 要求N < size，否则报参数警告，可通过关闭参数警告不编译这一段，提高效率
  HSK_LOG_PARM_WARN(
  if (N >= (_this->_end - _this->_begin) / _this->_tsize)
    printf("[VecGet PARM WARN]: N %zu >= size %zu is unexpected, capacity = %zu.\n", N, VecGetSize(_this), VecGetCapa(_this));
  )
  return _this->_begin + _this->_tsize * N;
}

size_t VecGetSize(const Vector* const _this) {
  ASSERT_THIS_NOT_NULL(_this, "VecGetSize", , 0);
  return (_this->_end - _this->_begin) / _this->_tsize;
}

size_t VecGetCapa(const Vector* const _this) {
  ASSERT_THIS_NOT_NULL(_this, "VecGetCapa", , 0);
  return (_this->_last - _this->_begin) / _this->_tsize;
}

void VecDispMsg(const Vector* const _this) {
  ASSERT_THIS_NOT_NULL(_this, "VecDispMsg", , );
  printf("this.size = %zu, this.capa = %zu, this.typesize = %zu.\n", VecGetSize(_this), VecGetCapa(_this), _this->_tsize);
}
